home *** CD-ROM | disk | FTP | other *** search
/ Developer CD Series 2000 November: Tool Chest / Dev.CD Nov 00 TC Disk 1.toast / Sample Code / Contributed / SpriteWorld / SpriteWorld Examples / SimpleBreakOut / SimpleBreakOut.c < prev    next >
Encoding:
C/C++ Source or Header  |  2000-10-06  |  16.2 KB  |  595 lines  |  [TEXT/CWIE]

  1. ///--------------------------------------------------------------------------------------
  2. // SimpleBreakOut.c
  3. //
  4. // Portions are Copyright © 1993 Tony Myles, All rights reserved worldwide.
  5. //
  6. // Description: This is a very basic breakout type game that demonstrates
  7. // SpriteWorld's efficient handling of inactive sprites.
  8. ///--------------------------------------------------------------------------------------
  9.  
  10.  
  11. #include <SWIncludes.h>            // Automatically include all SpriteWorld.h files
  12. #include <SWGameUtils.h>
  13.  
  14. #include "SWApplication.h"
  15. #include "SimpleBreakOut.h"
  16.  
  17.  
  18.  
  19. #define kMaxFPS                    60                // Set to 0 for maximum speed
  20. #define kSyncToVBL                false            // Sync animation to VBL?
  21.  
  22.  
  23. enum
  24. {
  25.     kBallHorizDelta = 5,
  26.     kBallVertDelta = 5,
  27.     kNumberOfBrickColumns = 10,
  28.     kNumberOfBrickRows = 5,
  29.     kTotalNumberOfBricks = (kNumberOfBrickColumns * kNumberOfBrickRows),
  30.     kBrickCIconID = 129,
  31.     kBreakBallCIconID = 130,
  32.     kPaddleCIconID = 131
  33. };
  34.  
  35.  
  36.  
  37. Point        oldPoint, newPoint;            // Mouse variables used for moving paddle
  38. short        gBrickNum;
  39.  
  40.  
  41. ///--------------------------------------------------------------------------------------
  42. // main
  43. ///--------------------------------------------------------------------------------------
  44.  
  45. void main(void)
  46. {
  47.     WindowPtr    myWindowP = NULL;
  48.     Rect        windRect;
  49.     
  50.     
  51.     Initialize(kNumberOfMoreMastersCalls);
  52.     
  53.     if (!SWHasSystem7())
  54.         CantRunOnThisMachine();
  55.  
  56.  
  57.         // Create and set up the window
  58.     myWindowP = GetNewCWindow(kWindowResID, NULL, (WindowPtr)-1L);
  59.  
  60.     if (myWindowP != NULL)
  61.     {
  62.             // Center window in screen
  63.         windRect = myWindowP->portRect;
  64.         CenterRect(&windRect, &qd.screenBits.bounds);
  65.         MoveWindow(myWindowP, windRect.left, windRect.top, false);
  66.         
  67.         ShowWindow(myWindowP);
  68.         SetPort(myWindowP);
  69.     }
  70.     else
  71.         CantFindResource();
  72.     
  73.  
  74.     PerformSimpleAnimation((CWindowPtr)myWindowP);
  75. }
  76.  
  77.  
  78. ///--------------------------------------------------------------------------------------
  79. // PerformSimpleAnimation
  80. ///--------------------------------------------------------------------------------------
  81.  
  82. void PerformSimpleAnimation(CWindowPtr srcWindowP)
  83. {
  84.     OSErr                    err;
  85.     PixPatHandle        pixPatH;
  86.     
  87.     SpriteWorldPtr        spriteWorldP;
  88.     SpriteLayerPtr        brickLayerP;
  89.     SpriteLayerPtr        ballLayerP;
  90.     SpriteLayerPtr        paddleLayerP;
  91.     SpritePtr            brickSpriteArray[kTotalNumberOfBricks];
  92.     SpritePtr            ballSpriteP;
  93.     SpritePtr            paddleSpriteP;
  94.     
  95.     short        horizOffset, vertOffset, brickHoriz, brickVert, col, row, n;
  96.     Rect        moveBoundsRect;
  97.  
  98.  
  99.     SetPort((GrafPtr)srcWindowP);
  100.     SetCursor(*GetCursor(watchCursor));
  101.  
  102.  
  103.     //
  104.     // STEP #1: initialize the sprite world package
  105.     //
  106.  
  107.     err = SWEnterSpriteWorld();
  108.     FatalError(err);
  109.  
  110.  
  111.     //
  112.     // STEP #2: create the various pieces that we need
  113.     //
  114.  
  115.         // create the sprite world
  116.     err = SWCreateSpriteWorldFromWindow(&spriteWorldP, srcWindowP, NULL, NULL, 0);
  117.     FatalError(err);
  118.  
  119.         // create the brick layer
  120.     err = SWCreateSpriteLayer(&brickLayerP);
  121.     FatalError(err);
  122.  
  123.         // create the ball layer
  124.     err = SWCreateSpriteLayer(&ballLayerP);
  125.     FatalError(err);
  126.  
  127.         // create the paddle layer
  128.     err = SWCreateSpriteLayer(&paddleLayerP);
  129.     FatalError(err);
  130.  
  131.         // Create the first brick sprite
  132.     err = SWCreateSpriteFromCicnResource(spriteWorldP, &(brickSpriteArray[0]), NULL, 
  133.                 kBrickCIconID, 1, kNoMask);
  134.  
  135.         // Clone the other brick sprites off the first one
  136.     for (gBrickNum = 1; gBrickNum < kTotalNumberOfBricks; gBrickNum++)
  137.     {
  138.         err = SWCloneSprite(brickSpriteArray[0], &brickSpriteArray[gBrickNum], NULL);
  139.         FatalError(err);
  140.     }
  141.  
  142.         // create ball sprite
  143.     err = SWCreateSpriteFromCicnResource(spriteWorldP, &ballSpriteP, NULL, 
  144.                 kBreakBallCIconID, 1, kFatMask);
  145.     FatalError(err);
  146.  
  147.         // create paddle sprite
  148.     err = SWCreateSpriteFromCicnResource(spriteWorldP, &paddleSpriteP, NULL, 
  149.                 kPaddleCIconID, 1, kFatMask);
  150.     FatalError(err);
  151.  
  152.  
  153.  
  154.     //
  155.     // STEP #3: put the pieces together (must be done BEFORE the sprite world is locked!)
  156.     //
  157.  
  158.     for (gBrickNum = 0; gBrickNum < kTotalNumberOfBricks; gBrickNum++)
  159.     {
  160.             // add the brick sprite to the brick layer
  161.         SWAddSprite(brickLayerP, brickSpriteArray[gBrickNum]);
  162.     }
  163.  
  164.         // add the ball sprite to the ball layer
  165.     SWAddSprite(ballLayerP, ballSpriteP);
  166.  
  167.         // add the paddle sprite to the paddle layer
  168.     SWAddSprite(paddleLayerP, paddleSpriteP);
  169.  
  170.         // add the layers to the world
  171.     SWAddSpriteLayer(spriteWorldP, brickLayerP);
  172.     SWAddSpriteLayer(spriteWorldP, ballLayerP);
  173.     SWAddSpriteLayer(spriteWorldP, paddleLayerP);
  174.     
  175.  
  176.  
  177.     //
  178.     // STEP #4: set things up for the animation
  179.     // (can be done before or after locking the SpriteWorld)
  180.     //
  181.  
  182.         // calculate the movement boundary rectangle
  183.     moveBoundsRect = srcWindowP->portRect;
  184.  
  185.     horizOffset = (brickSpriteArray[0]->curFrameP->frameRect.right - brickSpriteArray[0]->curFrameP->frameRect.left) + 2;
  186.     vertOffset = (brickSpriteArray[0]->curFrameP->frameRect.bottom - brickSpriteArray[0]->curFrameP->frameRect.top) + 2;
  187.     brickHoriz = 2;
  188.     brickVert = (vertOffset * 2);
  189.     gBrickNum = 0;
  190.  
  191.         // set up the bricks
  192.     for (col = 0; col < kNumberOfBrickColumns; col++)
  193.     {
  194.         brickVert = (vertOffset * 2);
  195.  
  196.         for (row = 0; row < kNumberOfBrickRows; row++)
  197.         {
  198.                 // set the sprite’s initial location
  199.             SWSetSpriteLocation(brickSpriteArray[gBrickNum], brickHoriz, brickVert);
  200.             SWSetSpriteMoveTime(brickSpriteArray[gBrickNum], -1);
  201.  
  202.             gBrickNum++;
  203.             brickVert += vertOffset;
  204.         }
  205.     
  206.         brickHoriz += horizOffset;
  207.     }
  208.  
  209.         // set the ball’s movement characteristics
  210.     SWSetSpriteLocation(ballSpriteP, - 100, 50);
  211.     SWSetSpriteMoveBounds(ballSpriteP, &moveBoundsRect);
  212.     SWSetSpriteMoveDelta(ballSpriteP, kBallHorizDelta, kBallVertDelta);
  213.     SWSetSpriteMoveProc(ballSpriteP, BallMoveProc);
  214.     SWSetSpriteCollideProc(ballSpriteP, BallCollideProc);
  215.  
  216.         // set the paddle’s movement characteristics
  217.     SWSetSpriteMoveBounds(paddleSpriteP, &moveBoundsRect);
  218.     SetUpPaddle(paddleSpriteP);
  219.     SWSetSpriteMoveProc(paddleSpriteP, PaddleMoveProc);
  220.     SWSetSpriteCollideProc(paddleSpriteP, PaddleCollideProc);
  221.     
  222.     
  223.     //
  224.     // Set the DrawProcs to BlitPixie
  225.     //
  226.  
  227.     if (spriteWorldP->pixelDepth >= 8)        // 8-bit, 16-bit, and 32-bit blitter
  228.     {
  229.         SWSetSpriteDrawProc(ballSpriteP, BlitPixieMaskDrawProc);
  230.         SWSetSpriteDrawProc(paddleSpriteP, BlitPixieMaskDrawProc);
  231.     }
  232.     else if ( SW_68K )                        // 68k blitter for any depth
  233.     {
  234.         SWSetSpriteDrawProc(ballSpriteP, BlitPixieAllBitMaskDrawProc);
  235.         SWSetSpriteDrawProc(paddleSpriteP, BlitPixieAllBitRectDrawProc);
  236.     }
  237.     
  238.  
  239.         // Set the screen and offscreen drawProcs
  240.     if (spriteWorldP->pixelDepth >= 8)        // 8-bit, 16-bit, and 32-bit blitter
  241.     {
  242.         SWSetSpriteWorldScreenDrawProc(spriteWorldP, BlitPixieRectDrawProc);
  243.         SWSetSpriteWorldOffscreenDrawProc(spriteWorldP, BlitPixieRectDrawProc);
  244.     }
  245.     else if ( SW_68K )                        // 68k blitter for any depth
  246.     {
  247.         SWSetSpriteWorldOffscreenDrawProc(spriteWorldP, BlitPixieAllBitRectDrawProc);
  248.         SWSetSpriteWorldScreenDrawProc(spriteWorldP, BlitPixieAllBitRectDrawProc);
  249.     }
  250.  
  251.  
  252.     //
  253.     // STEP #5: lock the sprite world        !!! VERY IMPORTANT !!!
  254.     //
  255.  
  256.     SWLockSpriteWorld(spriteWorldP);
  257.     
  258.  
  259.     HideCursor();
  260.     
  261.     
  262.     //
  263.     // SETP #6: Draw a nice background. Must be done *after* locking the SpriteWorld!
  264.     //
  265.  
  266.     SWSetPortToBackground(spriteWorldP);
  267.     
  268.     if (spriteWorldP->pixelDepth == 1)
  269.         pixPatH = GetPixPat(129);        // B&W dithered background
  270.     else
  271.         pixPatH = GetPixPat(128);        // Color
  272.     
  273.     if (pixPatH != NULL)
  274.     {
  275.         FillCRect(&moveBoundsRect, pixPatH);
  276.         DisposePixPat(pixPatH);
  277.     }
  278.  
  279.  
  280.     SWSetPortToWindow(spriteWorldP);
  281.  
  282.  
  283.     //
  284.     // STEP #7: update the SpriteWorld and run the animation
  285.     //
  286.  
  287.  
  288.     SetCursor(&qd.arrow);
  289.     SWUpdateSpriteWorld(spriteWorldP, true);
  290.     SWSetSpriteWorldMaxFPS( spriteWorldP, kMaxFPS );
  291.     SWSyncSpriteWorldToVBL(spriteWorldP, kSyncToVBL);
  292.     SWSetCleanUpSpriteWorld(spriteWorldP);
  293.     
  294.     FatalError( SWStickyError() ); // Make sure no errors got past us during setup
  295.     
  296.     while (!Button())
  297.     {
  298.         SWProcessSpriteWorld(spriteWorldP);
  299.  
  300.             // did we lose the last ball?
  301.         if (ballSpriteP->userData == 4)
  302.         {
  303.             SysBeep(1);
  304.             break;
  305.         }
  306.         else if (gBrickNum == 0)
  307.         {
  308.             for (n=0; n<3; n++)
  309.                 SysBeep(1);
  310.             break;
  311.         }
  312.  
  313.             // see if the ball has hit the paddle
  314.         SWCollideSpriteLayer(spriteWorldP, paddleLayerP, ballLayerP);
  315.  
  316.             // see if the ball has hit the bricks
  317.         SWCollideSpriteLayer(spriteWorldP, ballLayerP, brickLayerP);
  318.         
  319.             // Make sure no errors occurred during a MoveProc, etc.
  320.         FatalError( SWStickyError() );
  321.  
  322.         SWAnimateSpriteWorld(spriteWorldP);
  323.     }
  324.  
  325.  
  326.     //
  327.     // STEP #8: Clean up
  328.     //
  329.  
  330.     SWUnlockSpriteWorld(spriteWorldP);
  331.     SWDisposeSpriteWorld(&spriteWorldP);
  332.     SWExitSpriteWorld();
  333.     
  334.     FlushEvents(everyEvent, 0);
  335.     InitCursor();
  336. }
  337.  
  338.  
  339. ///--------------------------------------------------------------------------------------
  340. // BallCollideProc
  341. ///--------------------------------------------------------------------------------------
  342.  
  343. SW_FUNC void BallCollideProc(SpritePtr ballSpriteP, SpritePtr brickSpriteP, Rect* sectRect)
  344. {
  345.     short        offset;
  346.     short        vertMoveDelta = ballSpriteP->vertMoveDelta;
  347.     short        horizMoveDelta = ballSpriteP->horizMoveDelta;
  348.  
  349.  
  350.     if (vertMoveDelta < 0)
  351.         vertMoveDelta = -vertMoveDelta;
  352.     
  353.     if (horizMoveDelta < 0)
  354.         horizMoveDelta = -horizMoveDelta;
  355.     
  356.     if (brickSpriteP->isVisible)
  357.     {
  358.         SWSetSpriteVisible(brickSpriteP, false);
  359.         gBrickNum--;
  360.  
  361.  
  362.         
  363.         if (vertMoveDelta < sectRect->bottom - sectRect->top)
  364.         {
  365.                 // Hit left or right side of brick
  366.             
  367.                 // Reverse direction
  368.             ballSpriteP->horizMoveDelta = -ballSpriteP->horizMoveDelta;
  369.             
  370.                 // "Bounce" ball off bricks
  371.             offset = (sectRect->right - sectRect->left) * 2;
  372.             if (ballSpriteP->horizMoveDelta < 0)
  373.                 offset = -offset;
  374.             
  375.             SWOffsetSprite(ballSpriteP, offset, 0);
  376.         }
  377.         else if (horizMoveDelta < sectRect->right - sectRect->left)
  378.         {
  379.                 // Hit top or bottom of brick
  380.             
  381.                 // Reverse direction
  382.             ballSpriteP->vertMoveDelta = -ballSpriteP->vertMoveDelta;
  383.             
  384.                 // "Bounce" ball off bricks
  385.             offset = (sectRect->bottom - sectRect->top) * 2;
  386.             if (ballSpriteP->vertMoveDelta < 0)
  387.                 offset = -offset;
  388.             
  389.             SWOffsetSprite(ballSpriteP, 0, offset);
  390.         }
  391.         else
  392.         {
  393.                 // Hit corner of brick
  394.                 
  395.             if ((sectRect->right - sectRect->left) > (sectRect->bottom - sectRect->top) )
  396.             {
  397.                     // Hit left or right side of brick
  398.                 
  399.                     // Reverse direction
  400.                 ballSpriteP->horizMoveDelta = -ballSpriteP->horizMoveDelta;
  401.                 
  402.                     // "Bounce" ball off bricks
  403.                 offset = (sectRect->right - sectRect->left) * 2;
  404.                 if (ballSpriteP->horizMoveDelta < 0)
  405.                     offset = -offset;
  406.                 
  407.                 SWOffsetSprite(ballSpriteP, offset, 0);
  408.             }
  409.             else
  410.             {
  411.                     // Hit top or bottom of brick
  412.                 
  413.                     // Reverse direction
  414.                 ballSpriteP->vertMoveDelta = -ballSpriteP->vertMoveDelta;
  415.                 
  416.                     // "Bounce" ball off bricks
  417.                 offset = (sectRect->bottom - sectRect->top) * 2;
  418.                 if (ballSpriteP->vertMoveDelta < 0)
  419.                     offset = -offset;
  420.                 
  421.                 SWOffsetSprite(ballSpriteP, 0, offset);
  422.             }
  423.         }
  424.     }
  425. }
  426.  
  427.  
  428. ///--------------------------------------------------------------------------------------
  429. // PaddleCollideProc
  430. ///--------------------------------------------------------------------------------------
  431.  
  432. SW_FUNC void PaddleCollideProc(SpritePtr paddleSpriteP, SpritePtr ballSpriteP, Rect* sectRect)
  433. {
  434.     short    paddleMid = (paddleSpriteP->destFrameRect.right - 
  435.                             paddleSpriteP->destFrameRect.left)/2;
  436.     short    ballMid = (ballSpriteP->destFrameRect.right - 
  437.                             ballSpriteP->destFrameRect.left)/2;
  438.             
  439.     if ( (ballSpriteP->destFrameRect.bottom - ballSpriteP->vertMoveDelta) 
  440.             > paddleSpriteP->destFrameRect.bottom )
  441.         return;                            // Return if ball did not hit above bottom of paddle
  442.     
  443.     
  444.         // Set ball direction according to position hit on paddle
  445.     if (ballSpriteP->destFrameRect.left + ballMid >
  446.          paddleSpriteP->destFrameRect.left + paddleMid)
  447.     {
  448.         ballSpriteP->horizMoveDelta = ( (ballSpriteP->destFrameRect.left + ballMid) - 
  449.                 (paddleSpriteP->destFrameRect.left + paddleMid) )/4;
  450.                 
  451.         if (ballSpriteP->horizMoveDelta > 0)
  452.             ballSpriteP->vertMoveDelta = kBallVertDelta - ballSpriteP->horizMoveDelta/2;
  453.         else
  454.             ballSpriteP->vertMoveDelta = kBallVertDelta + ballSpriteP->horizMoveDelta/2;
  455.         
  456.         if (ballSpriteP->horizMoveDelta == 0)
  457.             ballSpriteP->horizMoveDelta++;
  458.     }
  459.     else
  460.     {
  461.         ballSpriteP->horizMoveDelta = ( (ballSpriteP->destFrameRect.left + ballMid) - 
  462.                 (paddleSpriteP->destFrameRect.left + paddleMid) )/4;
  463.                 
  464.         if (ballSpriteP->horizMoveDelta > 0)
  465.             ballSpriteP->vertMoveDelta = kBallVertDelta - ballSpriteP->horizMoveDelta/2;
  466.         else
  467.             ballSpriteP->vertMoveDelta = kBallVertDelta + ballSpriteP->horizMoveDelta/2;
  468.         
  469.         if (ballSpriteP->horizMoveDelta == 0)
  470.             ballSpriteP->horizMoveDelta--;
  471.     }
  472.  
  473.     
  474.         // If ball was moving down, turn it around
  475.     if (ballSpriteP->vertMoveDelta > 0)
  476.         ballSpriteP->vertMoveDelta = -ballSpriteP->vertMoveDelta;
  477.     
  478.     if ( (ballSpriteP->destFrameRect.bottom - ballSpriteP->vertMoveDelta) 
  479.             > paddleSpriteP->destFrameRect.top )
  480.     {
  481.         SWOffsetSprite(ballSpriteP, 0, sectRect->top - sectRect->bottom);
  482.     }
  483.     
  484. }
  485.  
  486.  
  487. ///--------------------------------------------------------------------------------------
  488. // SetUpPaddle
  489. ///--------------------------------------------------------------------------------------
  490.  
  491. SW_FUNC void SetUpPaddle(SpritePtr paddleSpriteP)
  492. {
  493.     short    middle = (paddleSpriteP->moveBoundsRect.right - 
  494.                         paddleSpriteP->moveBoundsRect.left) / 2;
  495.     short    paddleWidth = (paddleSpriteP->destFrameRect.right - 
  496.                             paddleSpriteP->destFrameRect.left);
  497.     Point    globalPoint;
  498.     
  499.     
  500.     GetMouse(&newPoint);
  501.     globalPoint = newPoint;
  502.     LocalToGlobal(&globalPoint);
  503.     
  504.     if (globalPoint.h < middle)
  505.     {
  506.         SWSetSpriteLocation(paddleSpriteP, paddleSpriteP->moveBoundsRect.left +
  507.                                     globalPoint.h, paddleSpriteP->moveBoundsRect.bottom - 30);
  508.     }
  509.     else if (qd.screenBits.bounds.right - globalPoint.h < middle)
  510.     {
  511.         SWSetSpriteLocation(paddleSpriteP, paddleSpriteP->moveBoundsRect.right+1 -
  512.                                     (qd.screenBits.bounds.right - globalPoint.h) - paddleWidth, 
  513.                                     paddleSpriteP->moveBoundsRect.bottom - 30);
  514.     }
  515.     else
  516.     {
  517.         SWSetSpriteLocation(paddleSpriteP, paddleSpriteP->moveBoundsRect.left +
  518.                         middle - paddleWidth/2, paddleSpriteP->moveBoundsRect.bottom - 30);
  519.     }
  520. }
  521.  
  522.  
  523. ///--------------------------------------------------------------------------------------
  524. // PaddleMoveProc
  525. ///--------------------------------------------------------------------------------------
  526.  
  527. SW_FUNC void PaddleMoveProc(SpritePtr paddleSpriteP)
  528. {
  529.     oldPoint = newPoint;
  530.     GetMouse(&newPoint);
  531.  
  532.     SWOffsetSprite(paddleSpriteP, newPoint.h - oldPoint.h, 0);
  533.     
  534.     if (paddleSpriteP->destFrameRect.left < paddleSpriteP->moveBoundsRect.left)
  535.     {
  536.         SWOffsetSprite(paddleSpriteP, (paddleSpriteP->moveBoundsRect.left - 
  537.                             paddleSpriteP->destFrameRect.left) , 0);
  538.     }
  539.     else if (paddleSpriteP->destFrameRect.right > paddleSpriteP->moveBoundsRect.right)
  540.     {
  541.         SWOffsetSprite(paddleSpriteP, (paddleSpriteP->moveBoundsRect.right - 
  542.                             paddleSpriteP->destFrameRect.right) , 0);
  543.     }
  544. }
  545.  
  546.  
  547. ///--------------------------------------------------------------------------------------
  548. // BallMoveProc
  549. ///--------------------------------------------------------------------------------------
  550.  
  551. SW_FUNC void BallMoveProc(SpritePtr srcSpriteP)
  552. {
  553.     register short         inset;
  554.     
  555.     
  556.         // Move the sprite
  557.     SWOffsetSprite(srcSpriteP, srcSpriteP->horizMoveDelta, srcSpriteP->vertMoveDelta);
  558.     
  559.  
  560.         // Check for collision with walls
  561.     if ((SWGetSpriteHorizLoc(srcSpriteP) < srcSpriteP->moveBoundsRect.left) &&
  562.             (srcSpriteP->horizMoveDelta < 0))        // Past left bounds and moving left
  563.     {
  564.         srcSpriteP->horizMoveDelta *= -1;            // Reverse direction
  565.         inset = srcSpriteP->moveBoundsRect.left - SWGetSpriteHorizLoc(srcSpriteP);
  566.         SWOffsetSprite( srcSpriteP, inset * 2, 0 );    // "Bounce" sprite off bounds
  567.  
  568.     }
  569.     else if ((srcSpriteP->destFrameRect.right > srcSpriteP->moveBoundsRect.right)&&
  570.                 (srcSpriteP->horizMoveDelta > 0))    // Past right bounds and moving right
  571.     {
  572.         srcSpriteP->horizMoveDelta *= -1;            // Reverse direction
  573.         inset = srcSpriteP->moveBoundsRect.right - srcSpriteP->destFrameRect.right;
  574.         SWOffsetSprite( srcSpriteP, inset * 2, 0 );    // "Bounce" sprite off bounds
  575.     }
  576.  
  577.     if ((SWGetSpriteVertLoc(srcSpriteP) < srcSpriteP->moveBoundsRect.top) &&
  578.             (srcSpriteP->vertMoveDelta < 0))        // Past top bounds and moving up
  579.     {
  580.         srcSpriteP->vertMoveDelta *= -1;            // Reverse direction
  581.         inset = srcSpriteP->moveBoundsRect.top - SWGetSpriteVertLoc(srcSpriteP);
  582.         SWOffsetSprite( srcSpriteP, 0, inset * 2 );    // "Bounce" sprite off bounds
  583.     }
  584.     else if ((srcSpriteP->oldFrameRect.top > srcSpriteP->moveBoundsRect.bottom)&&
  585.                 (srcSpriteP->vertMoveDelta > 0))    // Past bottom bounds and moving down
  586.     {
  587.         SysBeep(1);
  588.         srcSpriteP->userData++;
  589.  
  590.         SWSetSpriteLocation(srcSpriteP, -100, 50);
  591.  
  592.         SWSetSpriteMoveDelta(srcSpriteP, kBallHorizDelta, kBallVertDelta);
  593.     }
  594. }
  595.